// Fill out your copyright notice in the Description page of Project Settings.


#include "FoodGeneratorBase.h"

#include "BlockWallBase.h"
#include "FoodItemBase.h"
#include "SnakeBase.h"
#include "SnakeElementBase.h"
#include "Kismet/GameplayStatics.h"

// Sets default values
AFoodGeneratorBase::AFoodGeneratorBase()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;
}

// Called when the game starts or when spawned
void AFoodGeneratorBase::BeginPlay()
{
	Super::BeginPlay();

	FillAllBlockWalls();
}

// Called every frame
void AFoodGeneratorBase::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

void AFoodGeneratorBase::SetSnakeActor(ASnakeBase* Snake)
{
	SnakeActor = Snake;
}

void AFoodGeneratorBase::Run()
{
	CreateFoodItem();
}

void AFoodGeneratorBase::CreateFoodItem()
{
	auto AvailableCells = GetAvailableCells();

	if (AvailableCells.Num() > 0 && FoodForWin > 0)
	{
		const int32 CellIndex = FMath::RandRange(0, AvailableCells.Num() - 1);
		
		const auto FoodItem = GetWorld()->SpawnActor<AFoodItemBase>(FoodItemActorClass, FTransform(AvailableCells[CellIndex]));
	
		FoodItem->OnDestroyed.AddDynamic(this, &AFoodGeneratorBase::OnFoodItemDestroyHandler);
	}
	else
	{
		OnFoodEndedDelegate.Broadcast();
	}
}

TArray<FVector> AFoodGeneratorBase::GetAvailableCells()
{
	TArray<FVector> AvailableCells;

	// Fill
	for (int Row = 0; Row < RowCellsCount; Row++)
	{
		for (int Col = 0; Col < ColumnCellsCount; Col++)
		{
			AvailableCells.Add(FVector((Col * CellSize) + GetActorLocation().X, (Row * CellSize) + GetActorLocation().Y, 50));
		}
	}

	// Remove walls
	if (BlockWalls.Num() > 0)
	{
		for (const auto BlockWall : BlockWalls)
		{
			const int32 FindIndex = AvailableCells.Find(BlockWall->GetActorLocation());
	
			if (FindIndex != INDEX_NONE)
			{
				AvailableCells.RemoveAt(FindIndex);
			}
		}
	}

	// Remove snake elements
	if (SnakeActor->GetElements().Num() > 0)
	{
		for (const auto SnakeElement : SnakeActor->GetElements())
		{
			const int32 FindIndex = AvailableCells.Find(SnakeElement->GetActorLocation());
	
			if (FindIndex != INDEX_NONE)
			{
				AvailableCells.RemoveAt(FindIndex);
			}
		}
	}

	return AvailableCells;
}

void AFoodGeneratorBase::FillAllBlockWalls()
{
	TArray<AActor*> ActorsToFind;
	UGameplayStatics::GetAllActorsOfClass(GetWorld(), ABlockWallBase::StaticClass(), ActorsToFind);

	for (auto Actor : ActorsToFind)
	{
		BlockWalls.Add(Cast<ABlockWallBase>(Actor));
	}
}

void AFoodGeneratorBase::OnFoodItemDestroyHandler(AActor* DestroyedActor)
{
	FoodForWin--;
	
	OnFoodEatenDelegate.Broadcast();
	
	CreateFoodItem();
}
